/*
 *--------------------------------------------------------------------------
 *   File Name:	system.c
 * 
 * Description:	none
 * 
 * 
 *      Author:	Zhao Yanbai [zhaoyanbai@126.com]
 * 
 *     Version:	1.0
 * Create Date: Wed Mar  4 21:34:47 2009
 * Last Update: Wed Mar  4 21:34:47 2009
 * 
 *--------------------------------------------------------------------------
 */

#include<system.h>
#include<processor.h>
#include<string.h>
#include<page.h>
#include<irq.h>
#include<sched.h>
#include<i8259A.h>

void	SetupGDT()
{
	pDesc	pdesc;
	//change to new gdt.
	sgdt();
	memcpy(gdt, (void *)*((unsigned long*)(gdtr+2)),
				*((unsigned short *)gdtr));
	*((unsigned short *)gdtr)	= NGDT*sizeof(Desc);
	*((unsigned long  *)(gdtr+2))	= (unsigned long)gdt;
	lgdt();
	memcpy(gdt+INDEX_UCODE, gdt+INDEX_KCODE, sizeof(Desc));
	memcpy(gdt+INDEX_UDATA, gdt+INDEX_KDATA, sizeof(Desc));
	pdesc = gdt+INDEX_UCODE;
	pdesc->seg.DPL = 3;
	pdesc = gdt+INDEX_UDATA;
	pdesc->seg.DPL = 3;
}

void	SetupIDT()
{
	//init idt.
	*((unsigned short *)idtr)	= NIDT*sizeof(Gate);
	*((unsigned long  *)(idtr+2))	= (unsigned long)idt;
	lidt();
}
void no_irq_handler()
{
	printk("no_irq_handler");
	while(1);
}

void	SetupGate()
{	int i;
	extern	void	DivideError();
	extern	void	Debug();
	extern	void	NMI();
	extern	void	BreakPoint();
	extern	void	OverFlow();
	extern	void	BoundsCheck();
	extern	void	InvalidOpcode();
	extern	void	DeviceNotAvailable();
	extern	void	DoubleFault();
	extern	void	CoprocSegOverRun();
	extern	void	InvalidTss();
	extern	void	SegNotPresent();
	extern	void	StackFault();
	extern	void	GeneralProtection();
	extern	void	PageFault();
	extern	void	CoprocError();
#define	set_sys_int(vect, type, DPL, handler) \
	set_idt_gate(vect, (u32)handler, type, DPL)
#define	PL_KRNL	PRIVILEGE_KRNL
#define	PL_USER	PRIVILEGE_USER
#if 1
	set_sys_int(0x00, TRAP_GATE, PL_KRNL, DivideError);
	set_sys_int(0x01, TRAP_GATE, PL_KRNL, Debug);
	set_sys_int(0x02, INTR_GATE, PL_KRNL, NMI);	
	set_sys_int(0x03, TRAP_GATE, PL_USER, BreakPoint);	
	set_sys_int(0x04, TRAP_GATE, PL_USER, OverFlow);	
	set_sys_int(0x05, TRAP_GATE, PL_USER, BoundsCheck);	
	set_sys_int(0x06, TRAP_GATE, PL_KRNL, InvalidOpcode);	
	set_sys_int(0x07, TRAP_GATE, PL_KRNL, DeviceNotAvailable);	
	set_sys_int(0x08, TRAP_GATE, PL_KRNL, DoubleFault);	
	set_sys_int(0x09, TRAP_GATE, PL_KRNL, CoprocSegOverRun);	
	set_sys_int(0x0A, TRAP_GATE, PL_KRNL, InvalidTss);	
	set_sys_int(0x0B, TRAP_GATE, PL_KRNL, SegNotPresent);	
	set_sys_int(0x0C, TRAP_GATE, PL_KRNL, StackFault);	
	set_sys_int(0x0D, TRAP_GATE, PL_KRNL, GeneralProtection);	
	set_sys_int(0x0E, TRAP_GATE, PL_KRNL, PageFault);	
	set_sys_int(0x10, TRAP_GATE, PL_KRNL, CoprocError);
	for(i=0x20; i<256; i++)
		set_sys_int(i, INTR_GATE, PL_KRNL, no_irq_handler);	
	extern	void	irq_0x00_handler();	
	extern	void	irq_0x01_handler();	
	set_sys_int(0x20, INTR_GATE, PL_KRNL, irq_0x00_handler);
	set_sys_int(0x21, INTR_GATE, PL_KRNL, irq_0x01_handler);	
#endif
}

IRQAction kbd_action;
IRQAction clk_action;
void	SetupIRQS()
{
	extern	void kbd_handler(pPTRegs, unsigned int);
	extern	void clk_handler(pPTRegs, unsigned int);
	int i;
	for(i=FIRST_IRQ_VECT; i<FIRST_IRQ_VECT+NR_IRQS; i++)
		irq_desc[i] = no_irq_desc;

	clk_action.handler = clk_handler;
	clk_action.next	= NULL;
	kbd_action.handler = kbd_handler;
	kbd_action.next = NULL;

	irq_desc[0x0].chip = &i8259A_chip;
	irq_desc[0x0].chip->enable(0x0);
	irq_desc[0x0].action = &clk_action;

	irq_desc[0x1].chip = &i8259A_chip;
	irq_desc[0x1].chip->enable(0x1);
	irq_desc[0x1].action = &kbd_action;

}

TSS	tss;
void	setTss()
{
	pTSS p = &tss;
	memset((void *)p, sizeof(TSS), 0);
	p->esp0		= ((u32)&RootTsk) + TASK_SIZE;
	p->ss0		= SELECTOR_KRNL_DS;
	p->ss		= SELECTOR_KRNL_DS;
	p->gs		= SELECTOR_KRNL_DS;
	p->fs		= SELECTOR_KRNL_DS;
	p->es		= SELECTOR_KRNL_DS;
	p->ds		= SELECTOR_KRNL_DS;
	p->cs		= SELECTOR_KRNL_CS;
	p->eflags	= 0x1200;
	p->iomap_base	= sizeof(TSS);
	set_tss_gate(INDEX_TSS, (u32)p);
	asm("ltr %%ax"::"a"((INDEX_TSS<<3)+3));
}
